package com.sulent.frame.web.handler;

import java.lang.reflect.Method;
import java.nio.file.AccessDeniedException;
import java.util.ArrayList;
import java.util.Iterator;
import java.util.Objects;
import javax.servlet.http.HttpServletRequest;
import javax.validation.ConstraintViolation;
import javax.validation.ConstraintViolationException;

import com.sulent.frame.support.entity.R;
import com.sulent.frame.support.exception.BusinessException;
import com.sulent.frame.support.exception.FileDownloadException;
import com.sulent.frame.support.utils.ResultUtil;
import org.apache.commons.lang3.StringUtils;
import org.omg.CORBA.SystemException;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.http.HttpStatus;
import org.springframework.http.converter.HttpMessageNotReadableException;
import org.springframework.validation.BindException;
import org.springframework.validation.BindingResult;
import org.springframework.validation.FieldError;
import org.springframework.web.HttpMediaTypeNotSupportedException;
import org.springframework.web.HttpRequestMethodNotSupportedException;
import org.springframework.web.bind.MethodArgumentNotValidException;
import org.springframework.web.bind.ServletRequestBindingException;
import org.springframework.web.bind.annotation.ExceptionHandler;
import org.springframework.web.bind.annotation.ResponseBody;
import org.springframework.web.bind.annotation.ResponseStatus;
import org.springframework.web.method.annotation.MethodArgumentTypeMismatchException;

public class BaseExceptionHandler {
    private static final Logger log = LoggerFactory.getLogger(BaseExceptionHandler.class);

    public BaseExceptionHandler() {
    }

    @ExceptionHandler({BusinessException.class})
    @ResponseBody
    public R BusinessExceptionHandler(HttpServletRequest req, BusinessException e) {
        log.error(String.format("BusinessException RequestURI::%s", req.getRequestURI()), e);
        return ResultUtil.error(e.getMessage());
    }

    @ExceptionHandler({MethodArgumentTypeMismatchException.class})
    @ResponseBody
    public R MethodArgumentTypeMismatchExceptionHandler(HttpServletRequest req, MethodArgumentTypeMismatchException e) {
        String builder = "参数转换失败，方法：" + ((Method)Objects.requireNonNull(e.getParameter().getMethod())).getName() + "，参数：" + e.getName() + ",信息：" + e.getLocalizedMessage();
        log.error("MethodArgumentNotValidException RequestURI:{} msg:{}", req.getRequestURI(), builder);
        return ResultUtil.error(400, "参数" + e.getName() + "类型不正确");
    }

    @ExceptionHandler({MethodArgumentNotValidException.class})
    @ResponseBody
    public R handleMethodArgumentNotValidException(HttpServletRequest req, MethodArgumentNotValidException e) {
        BindingResult bindingResult = e.getBindingResult();
        StringBuilder sb = new StringBuilder();
        sb.append("url=");
        sb.append(req.getRequestURI().replace("/", ""));
        sb.append(",");
        Iterator var5 = bindingResult.getFieldErrors().iterator();

        while(var5.hasNext()) {
            FieldError fieldError = (FieldError)var5.next();
            sb.append("field=");
            sb.append(fieldError.getObjectName());
            sb.append(".");
            sb.append(fieldError.getField());
            sb.append(",error=");
            sb.append(fieldError.getDefaultMessage());
            sb.append(";");
        }

        String msg = sb.toString();
        log.error(String.format("MethodArgumentNotValidException RequestURI:%s msg:%s", req.getRequestURI(), msg), e);
        return ResultUtil.error(400, bindingResult.getFieldError().getDefaultMessage());
    }

    @ExceptionHandler({ConstraintViolationException.class})
    @ResponseBody
    public R handleMethodArgumentNotValidException(HttpServletRequest req, ConstraintViolationException e) {
        Iterator<ConstraintViolation<?>> iterator = e.getConstraintViolations().iterator();
        ArrayList message = new ArrayList();

        while(iterator.hasNext()) {
            ConstraintViolation<?> violation = (ConstraintViolation)iterator.next();
            if (Objects.isNull(violation.getInvalidValue())) {
                message.add(String.format("参数“%s”%s", violation.getPropertyPath().toString(), violation.getMessage()));
            } else {
                message.add(String.format("“%s”%s", violation.getInvalidValue(), violation.getMessage()));
            }
        }

        log.error(String.format("ConstraintViolationException RequestURI:%s", req.getRequestURI()), e);
        return ResultUtil.error(400, StringUtils.join(message, "; "));
    }

    @ExceptionHandler({BindException.class})
    @ResponseBody
    public R handleBindException(HttpServletRequest req, BindException e) throws BindException {
        FieldError fieldError = e.getFieldError();
        StringBuilder sb = new StringBuilder();
        sb.append(fieldError.getDefaultMessage());
        log.error("BindException requestURI:{} paramName:{} msg:{}", new Object[]{req.getRequestURI(), e.getObjectName(), fieldError.getDefaultMessage()});
        return ResultUtil.error(400, fieldError.getDefaultMessage());
    }

    @ExceptionHandler({ServletRequestBindingException.class})
    @ResponseBody
    public R ServletRequestBindingExceptionHandler(HttpServletRequest req, ServletRequestBindingException e) {
        log.error("ServletRequestBindingException RequestURI:{},{}", req.getRequestURI(), e.getMessage());
        return ResultUtil.error(400, e.getMessage());
    }

    @ExceptionHandler({HttpMediaTypeNotSupportedException.class})
    @ResponseBody
    public R ServletRequestBindingExceptionHandler(HttpServletRequest req, HttpMediaTypeNotSupportedException e) {
        log.error("HttpMediaTypeNotSupportedException RequestURI:{},{}", req.getRequestURI(), e.getMessage());
        return ResultUtil.error(400, "错误的Content-Type");
    }

    @ExceptionHandler({HttpMessageNotReadableException.class})
    @ResponseBody
    public R ServletRequestBindingExceptionHandler(HttpServletRequest req, HttpMessageNotReadableException e) {
        log.error("HttpMessageNotReadableException RequestURI:{},{}", req.getRequestURI(), e.getMessage());
        return ResultUtil.error(400, "参数不合法");
    }

    @ExceptionHandler({SystemException.class})
    @ResponseBody
    public R handleSystemException(SystemException e) {
        log.error("系统异常", e);
        return ResultUtil.error(HttpStatus.INTERNAL_SERVER_ERROR.value(), "服务器内部错误");
    }

    @ExceptionHandler({FileDownloadException.class})
    @ResponseStatus(HttpStatus.INTERNAL_SERVER_ERROR)
    public void handleFileDownloadException(FileDownloadException e) {
        log.error("文件下载异常", e);
    }

    @ExceptionHandler({AccessDeniedException.class})
    @ResponseBody
    public R handleAccessDeniedException(HttpServletRequest req, AccessDeniedException e) {
        log.error(String.format("Exception requestURI:%s", req.getRequestURI()), e);
        return ResultUtil.error(HttpStatus.FORBIDDEN.value(), "没有权限访问该资源");
    }

    @ExceptionHandler({HttpRequestMethodNotSupportedException.class})
    @ResponseBody
    public R handleHttpRequestMethodNotSupportedException(HttpRequestMethodNotSupportedException e) {
        String message = "该方法不支持" + StringUtils.substringBetween(e.getMessage(), "'", "'") + "请求方法";
        log.error(message);
        return ResultUtil.error(HttpStatus.INTERNAL_SERVER_ERROR.value(), message);
    }

    @ExceptionHandler({Exception.class})
    @ResponseBody
    public R ExceptionHandler(HttpServletRequest req, Exception e) {
        log.error(String.format("Exception requestURI:%s", req.getRequestURI()), e);
        return ResultUtil.error(500, "服务器内部错误");
    }
}
